from django.shortcuts import render
from rest_framework import status
from rest_framework.views import APIView
from .serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer, CartSelectAllSerializer
from django_redis import get_redis_connection
from rest_framework.response import Response
import base64, pickle
from . import constants
from goods.models import SKU
# Create your views here.


class CartView(APIView):
    # 进入视图再判断用户是否登录
    def perform_authentication(self, request):
        pass

    def post(self, request):
        """添加购物车, 这里不是操作的数据库，所有保存逻辑自己写"""
        # 使用序列化器校验
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']
        print(selected)
        # 3.判断用户是否登录
        try:
            user = request.user
        except Exception:
            # 验证失败，用户未登录
            user = None
        # 判断用户已登录，并且是经过数据库查询验证的用户
        # 如果查询用户未查询到信息，user有时会返回anonymity匿名用户对象
        if user and user.is_authenticated:
            # 3.1登录保存到redis
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # 哈希的累加添加数据

            pl.hincrby('cart_%s' % user.id, sku_id, count)
            # 勾选的状态保存在redis的集合中
            if selected:
                pl.sadd('cart_selected_%s' % user.id, sku_id)
            pl.execute()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            # 3.2未登录保存到cookie
            cart_str = request.COOKIES.get('cart')
            # 我们从前端拿到的是字符串，要先编码成二进制才能给base64使用
            # 使用pickle序列化购物车数据，pickle操作的是bytes类型
            if cart_str is not None:
                cart_byte = cart_str.encode()
                cart = pickle.loads(base64.b64decode(cart_byte))
            else:
                cart = {}
            if sku_id in cart:
                cart[sku_id]['count'] = cart[sku_id]['count'] + count
                cart[sku_id]['selected'] = selected
            else:
                cart[sku_id] = {
                    'count': count,
                    'selected': selected
                }
            print(cart)
            cart_bytes = pickle.dumps(cart)
            cart_cookie = base64.b64encode(cart_bytes).decode()
            # print(cart_cookie)
            # 设置购物车的cookie
            # 需要设置有效期，否则是临时cookie
            response = Response(serializer.data, status=status.HTTP_200_OK)
            response.set_cookie('cart', cart_cookie, max_age=constants.CART_COOKIE_EXPIRES)
            return response

    def get(self, request):
        """获取用户的购物车信息"""
        # 1.前端不需要传入任何参数
        try:
            user = request.user
        except Exception:
            user = None

        if user is not None and user.is_authenticated:
            """这里用户是登录的状态，从redis中查询"""
            # 从redis中获取的数据都是bytes类型的，保存的时候，不需要关系类型
            redis_conn = get_redis_connection('cart')
            redis_cart = redis_conn.hgetall('cart_%s' % user.id)
            redis_cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)
            cart = {}
            for sku_id, count in redis_cart.items():
                # 查询数据库放在序列化器里面，　我们从redis中取到的bytes类型要进行转换
                cart[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in redis_cart_selected
                }
        else:
            """用户未登录，要从cookie中获取信息"""
            cookie_cart = request.COOKIES.get('cart')
            # 如果有获取到，转成我们需要的字典
            if cookie_cart is not None:
                cart = pickle.loads(base64.b64decode(cookie_cart.encode()))

            else:
                cart = {}
        # 我们都是拿到数据之后进行查询的，我们就把他们构造到同名的字典中，一起进行操作查询
        skus = SKU.objects.filter(id__in=cart.keys())

        # 给每个SKU添加两个属性
        for sku in skus:
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']
        # 使用序列化器构造返回数据
        serializer = CartSKUSerializer(skus, many=True)
        # print(serializer.data)
        return Response(serializer.data)

    def put(self, request):
        """修改购物车数据"""
        serializer = CartSerializer(data=request.data)
        # 使用幂等性，前端传送的是最终结果
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']
        # print(selected)
        # print(serializer.validated_data, 'test11111111111')
        # print(serializer.data,  'test22222222222')
        # 先判断用户的sku_id是否存在
        # 判断用户是否登陆
        try:
            user = request.user
        except Exception:
            user = None
        if user is not None and user.is_authenticated:
            # 这里说明用户是登陆且验证通过的,操作redis
            redis_conn = get_redis_connection('cart')
            # 需要修改多处数据，使用管道
            pl = redis_conn.pipeline()
            # 修改数量
            pl.hset('cart_%s' % user.id, sku_id, count)
            # 修改状态(集合类型，去重)
            if selected:
                pl.sadd('cart_selected_%s' % user.id, sku_id)
            else:
                pl.srem('cart_selected_%s' % user.id, sku_id)   # 删除不存在不会保存
            # 提交
            pl.execute()
            return Response(serializer.data)
        else:
            # 这里是用户未登陆，操作的是cookie
            cookie_cart = request.COOKIES.get('cart')
            # 判断用户购物车是否有数据
            if cookie_cart:
                # 我们在cookie中存的是字符串数据．需要进行解析
                cookie_cart = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                cookie_cart = {}
            if sku_id in cookie_cart.keys():
                cookie_cart[sku_id]['count'] = count
                cookie_cart[sku_id]['selected'] = selected
            # 再进行转换返回给前端
            cookie_cart = base64.b64encode(pickle.dumps(cookie_cart)).decode()
            response = Response(serializer.data)
            response.set_cookie('cart', cookie_cart, max_age=constants.CART_COOKIE_EXPIRES)
            return response

    def delete(self, request):
        # 请求参数sku_id  返回状态码204
        # sku_id = request.data.get('sku_id')　　　这样写是不对的，并没有校验
        # 前端传过来的数据还是要进行验证的
        serializer = CartDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data['sku_id']
        # 根据用户登录状态判断删除哪里的数据
        try:
            user = request.user
        except Exception:
            user = None
        if user is not None and user.is_authenticated:
            # 用户登录，操作redis
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            pl.hdel('cart_%s' % user.id, sku_id)
            pl.srem('cart_selected_%s' % user.id, sku_id)
            pl.execute()
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            # 用户未登录，删除cookie
            cookie_cart = request.COOKIES.get('cart')
            # 为什么总是不记得解成python认识的字典
            if cookie_cart:
                cookie_cart = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                cookie_cart = {}
            # 防止非法通过前端传过来无效数据
            if sku_id in cookie_cart.keys():
                del cookie_cart[sku_id]
            cookie_cart = base64.b64encode(pickle.dumps(cookie_cart)).decode()
            response = Response(status=status.HTTP_204_NO_CONTENT)
            # response.delete_cookie(cookie_cart, sku_id)   不是要删除整个cookie．只是把数据进行删除再返回
            response.set_cookie('cart', cookie_cart, max_age=constants.CART_COOKIE_EXPIRES)
            return response


class CartSelectAllView(APIView):
    """判断是全选还是取消全选"""
    # 进入视图再判断用户是否登录
    def perform_authentication(self, request):
        pass

    def put(self, request):
        serializer = CartSelectAllSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data['selected']
        try:
            user = request.user
        except Exception:
            user = None
        if user is not None and user.is_authenticated:
            # 登录，操作redis
            redis_conn = get_redis_connection('cart')
            # 需要删除集合中保存的所有sku_id, 获取哈希类型中该用户所有的key
            reids_cart = redis_conn.hgetall('cart_%s' % user.id)
            redis_sku_id = []
            for cart_sku_id in reids_cart.keys():
                redis_sku_id.append(cart_sku_id)
            if selected:
                redis_conn.sadd('cart_selected_%s' % user.id, *redis_sku_id)
            else:
                redis_conn.srem('cart_selected_%s' % user.id, *redis_sku_id)
            return Response({'message': 'OK'})
        else:
            # 未登录，操作cookie
            cookie_cart = request.COOKIES.get('cart')
            if cookie_cart:
                cookie_cart = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                cookie_cart = {}
            if selected:
                # 全选
                for sku_id, count_select in cookie_cart.items():
                    count_select['selected'] = True
            else:
                for sku_id, count_select in cookie_cart.items():
                    count_select['selected'] = False
            # 反转返回
            cookie_cart = base64.b64encode(pickle.dumps(cookie_cart)).decode()
            response = Response({'message': 'OK'})
            response.set_cookie('cart', cookie_cart, max_age=constants.CART_COOKIE_EXPIRES)
            return response
